/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * ConvertPanel.java
 *
 * Created on Mar 9, 2011, 8:37:11 PM
 */
package thesis.view;

import feature.ENTITY;
import java.awt.Color;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Highlighter;
import util.Config;
import util.ConvertText;
import util.GUIFunction;
import util.ReadWriteFile;
import util.Sentence;
import util.TextFilter;
import util.Word;
import thesis.MainFrame;

/**
 *
 * @author banhbaochay
 */
public class ConvertPanel extends javax.swing.JPanel {

    /**
     * Key luu gia tri size cua lineArea trong file config
     */
    public static final String LINE_FONT_SIZE = "line.font.size";

    /** Creates new form ConvertPanel
     * @param proper
     */
    public ConvertPanel(HashMap<String, String> mapConfig) {
        this.mapConfig = mapConfig;
        initData();
        initComponents();
        hilitOuput = new DefaultHighlighter();
        outputArea.setHighlighter(hilitOuput);
        hilitLine = new DefaultHighlighter();
        lineArea.setHighlighter(hilitLine);
    }

    // <editor-fold defaultstate="collapsed" desc="Init Data">
    private void initData() {
        count = 1;

        Object[] colInput = {"Line"};
        inputModel = new DefaultTableModel(colInput, 0);

        Object[] colConvert = {"Agent", "Target", "Label"};
        convertModel = new DefaultTableModel(colConvert, 0) {

            @Override
            public Class getColumnClass(int col) {
                return (col == 2) ? Boolean.class : Object.class;
            }
        };
    }
    // </editor-fold>

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        openDialog = new javax.swing.JDialog();
        jScrollPane1 = new javax.swing.JScrollPane();
        lineAreaDialog = new javax.swing.JTextArea();
        jLabel1 = new javax.swing.JLabel();
        popupMenu = new javax.swing.JPopupMenu();
        openItem = new javax.swing.JMenuItem();
        removeItem = new javax.swing.JMenuItem();
        mainPanel = new javax.swing.JPanel();
        jLabel2 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        outputArea = new javax.swing.JTextArea();
        jScrollPane4 = new javax.swing.JScrollPane();
        convertTable = new javax.swing.JTable();
        convertButton = new javax.swing.JButton();
        analyzeButton = new javax.swing.JButton();
        addButton = new javax.swing.JButton();
        removeButton = new javax.swing.JButton();
        clearOutputButton = new javax.swing.JButton();
        jScrollPane3 = new javax.swing.JScrollPane();
        inputTable = new javax.swing.JTable();
        loadButton = new javax.swing.JButton();
        clearButton = new javax.swing.JButton();
        saveButton = new javax.swing.JButton();
        resetCountButton = new javax.swing.JButton();
        jScrollPane5 = new javax.swing.JScrollPane();
        lineArea = new javax.swing.JTextArea();
        jLabel3 = new javax.swing.JLabel();
        SpinnerModel spinModel = new SpinnerNumberModel(14, 9, 30, 2);
        sizeSpinner = new javax.swing.JSpinner(spinModel);
        jLabel4 = new javax.swing.JLabel();
        savePathTF = new javax.swing.JTextField();

        openDialog.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        openDialog.setTitle("Line Content");
        openDialog.setName("openDialog"); // NOI18N

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        lineAreaDialog.setColumns(20);
        lineAreaDialog.setLineWrap(true);
        lineAreaDialog.setRows(5);
        lineAreaDialog.setName("lineAreaDialog"); // NOI18N
        jScrollPane1.setViewportView(lineAreaDialog);

        jLabel1.setText("Line content");
        jLabel1.setName("jLabel1"); // NOI18N

        javax.swing.GroupLayout openDialogLayout = new javax.swing.GroupLayout(openDialog.getContentPane());
        openDialog.getContentPane().setLayout(openDialogLayout);
        openDialogLayout.setHorizontalGroup(
            openDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addGroup(openDialogLayout.createSequentialGroup()
                .addGap(147, 147, 147)
                .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        openDialogLayout.setVerticalGroup(
            openDialogLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(openDialogLayout.createSequentialGroup()
                .addGap(16, 16, 16)
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE))
        );

        popupMenu.setName("popupMenu"); // NOI18N

        openItem.setText("Open");
        openItem.setName("openItem"); // NOI18N
        openItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openItemActionPerformed(evt);
            }
        });
        popupMenu.add(openItem);

        removeItem.setText("Remove");
        removeItem.setName("removeItem"); // NOI18N
        removeItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeItemActionPerformed(evt);
            }
        });
        popupMenu.add(removeItem);

        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

        jLabel2.setText("Output line");
        jLabel2.setName("jLabel2"); // NOI18N
        mainPanel.add(jLabel2, new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 510, -1, -1));

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        outputArea.setColumns(20);
        outputArea.setLineWrap(true);
        outputArea.setRows(5);
        outputArea.setName("outputArea"); // NOI18N
        jScrollPane2.setViewportView(outputArea);

        mainPanel.add(jScrollPane2, new org.netbeans.lib.awtextra.AbsoluteConstraints(90, 460, 840, 120));

        jScrollPane4.setName("jScrollPane4"); // NOI18N

        convertTable.setModel(convertModel);
        convertTable.setName("convertTable"); // NOI18N
        jScrollPane4.setViewportView(convertTable);

        mainPanel.add(jScrollPane4, new org.netbeans.lib.awtextra.AbsoluteConstraints(320, 270, 610, 130));

        convertButton.setMnemonic('C');
        convertButton.setText("Convert");
        convertButton.setToolTipText("Convert to JSRE format [Alt + C]");
        convertButton.setName("convertButton"); // NOI18N
        convertButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                convertButtonActionPerformed(evt);
            }
        });
        mainPanel.add(convertButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(300, 420, 90, -1));

        analyzeButton.setMnemonic('A');
        analyzeButton.setText(">>");
        analyzeButton.setToolTipText("Analyze sentence [Alt + A]");
        analyzeButton.setName("analyzeButton"); // NOI18N
        analyzeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                analyzeButtonActionPerformed(evt);
            }
        });
        mainPanel.add(analyzeButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(70, 290, 83, -1));

        addButton.setMnemonic('D');
        addButton.setText("Add");
        addButton.setToolTipText("Add relation A-T [Alt + D]");
        addButton.setName("addButton"); // NOI18N
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });
        mainPanel.add(addButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(70, 350, 83, -1));

        removeButton.setText("Remove");
        removeButton.setName("removeButton"); // NOI18N
        removeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeButtonActionPerformed(evt);
            }
        });
        mainPanel.add(removeButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(200, 290, 90, -1));

        clearOutputButton.setText("Clear output");
        clearOutputButton.setName("clearOutputButton"); // NOI18N
        clearOutputButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearOutputButtonActionPerformed(evt);
            }
        });
        mainPanel.add(clearOutputButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(460, 590, 120, -1));

        jScrollPane3.setName("jScrollPane3"); // NOI18N

        inputTable.setModel(inputModel);
        inputTable.setName("inputTable"); // NOI18N
        inputTable.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                inputTableMouseClicked(evt);
            }
        });
        inputTable.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                inputTableKeyReleased(evt);
            }
        });
        jScrollPane3.setViewportView(inputTable);
        MouseListener popupListener = new PopupListener();
        inputTable.addMouseListener(popupListener);

        mainPanel.add(jScrollPane3, new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 50, 530, 200));

        loadButton.setText("Load File");
        loadButton.setName("loadButton"); // NOI18N
        loadButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadButtonActionPerformed(evt);
            }
        });
        mainPanel.add(loadButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(60, 10, -1, -1));

        clearButton.setText("Clear");
        clearButton.setName("clearButton"); // NOI18N
        clearButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                clearButtonActionPerformed(evt);
            }
        });
        mainPanel.add(clearButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(200, 350, 90, -1));

        saveButton.setText("Save");
        saveButton.setName("saveButton"); // NOI18N
        saveButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveButtonActionPerformed(evt);
            }
        });
        mainPanel.add(saveButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(300, 590, 90, -1));

        resetCountButton.setText("Reset Count");
        resetCountButton.setName("resetCountButton"); // NOI18N
        resetCountButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resetCountButtonActionPerformed(evt);
            }
        });
        mainPanel.add(resetCountButton, new org.netbeans.lib.awtextra.AbsoluteConstraints(460, 420, 120, -1));

        jScrollPane5.setName("jScrollPane5"); // NOI18N

        lineArea.setColumns(20);
        lineArea.setLineWrap(true);
        lineArea.setRows(5);
        lineArea.setName("lineArea"); // NOI18N
        jScrollPane5.setViewportView(lineArea);

        mainPanel.add(jScrollPane5, new org.netbeans.lib.awtextra.AbsoluteConstraints(550, 50, 380, 200));

        jLabel3.setText("Size:");
        jLabel3.setName("jLabel3"); // NOI18N
        mainPanel.add(jLabel3, new org.netbeans.lib.awtextra.AbsoluteConstraints(690, 20, -1, -1));

        sizeSpinner.setName("sizeSpinner"); // NOI18N
        sizeSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sizeSpinnerStateChanged(evt);
            }
        });
        mainPanel.add(sizeSpinner, new org.netbeans.lib.awtextra.AbsoluteConstraints(720, 10, 50, -1));
        String size = mapConfig.get(Config.LINE_FONT_SIZE);
        sizeSpinner.setValue(Integer.parseInt(size));

        jLabel4.setText("Directory save");
        jLabel4.setName("jLabel4"); // NOI18N
        mainPanel.add(jLabel4, new org.netbeans.lib.awtextra.AbsoluteConstraints(190, 20, -1, -1));

        savePathTF.setEditable(false);
        savePathTF.setToolTipText("Click here to define directory to save");
        savePathTF.setName("savePathTF"); // NOI18N
        savePathTF.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                savePathTFMousePressed(evt);
            }
        });
        mainPanel.add(savePathTF, new org.netbeans.lib.awtextra.AbsoluteConstraints(290, 10, 350, -1));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 960, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(0, 0, Short.MAX_VALUE)
                    .addComponent(mainPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 960, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 0, Short.MAX_VALUE)))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 623, Short.MAX_VALUE)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(0, 3, Short.MAX_VALUE)
                    .addComponent(mainPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 3, Short.MAX_VALUE)))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void convertButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_convertButtonActionPerformed
        // TODO add your handling code here:
        int rowCount = convertModel.getRowCount();
        ArrayList<String> hilitAgentList = new ArrayList<String>();
        ArrayList<String> hilitTargetList = new ArrayList<String>();
        int idLine = rowLine + 1;
        for (int row = 0; row < rowCount; row++) {
            boolean status = (Boolean) convertModel.getValueAt(row, 2);
            boolean isAgent = false;
            boolean isTarget = false;
            int elementA = getOffsetFromCombo((String) convertModel.getValueAt(row, 0));
            int elementT = getOffsetFromCombo((String) convertModel.getValueAt(row, 1));
            StringBuilder result = new StringBuilder();
            int label = 0;
            int tokenID = 0;
            String token = null;
            String lemma = null;
            String POS = null;
            String entityType = null;
            String entityLabel = null;

            label = (status) ? 1 : 0;
            result.append(label);
            result.append("\t");
            result.append(idLine);
            result.append("-");
            result.append(count);
            result.append("\t");

            /* Write body, body has form: tokenID&&token&&lemma&&POS&&entityType&&entityLabel*/
            for (int i = 0; i < sentence.size(); i++) {
                if (entityMap.containsKey(i)) {
                    /* word at i offset is begin of entity string */
                    Object[] values = entityMap.get(i);
                    ENTITY entity = (ENTITY) values[0];
                    int beginOffset = (Integer) values[1];
                    int endOffset = (Integer) values[2];
                    token = getEntityWords(sentence, values);
                    token = token.substring(token.indexOf("-") + 1);
                    POS = "Np";
                    entityType = entity.getName();
                    if (i == elementA) {
                        entityLabel = "A";
                        isAgent = true;
                    } else if (i == elementT) {
                        entityLabel = "T";
                        isTarget = true;
                    } else {
                        entityLabel = "O";
                    }// end if i
                    i += (endOffset - beginOffset);
                } else {
                    /* word at i offset is normal word */
                    Word word = sentence.wordAt(i);
                    token = word.getForm();
                    POS = word.getPOS().getName();
                    if (POS.equals("Unknown")) {
                        // khi token chi la dau cham cau
                        POS = token;
                    }// end if POS
                    entityType = "O";
                    entityLabel = "O";
                }// end if entityMap
                lemma = token;

                StringBuilder sb = new StringBuilder();
                sb.append(tokenID);
                sb.append("&&");
                sb.append(token);
                sb.append("&&");
                sb.append(lemma);
                sb.append("&&");
                sb.append(POS);
                sb.append("&&");
                sb.append(entityType);
                sb.append("&&");
                sb.append(entityLabel);

                if (isAgent) {
                    hilitAgentList.add(sb.toString());
                    isAgent = false;
                } else if (isTarget) {
                    hilitTargetList.add(sb.toString());
                    isTarget = false;
                }// end isAgent

                result.append(sb);
                result.append(" ");

                tokenID++;
            }// end for i
            outputArea.append(result.toString());
            outputArea.append("\r\n");
            count++;
        }// end for row

        /*
         * Set highlight cho cac thanh phan trong output area
         */
        String outputText = outputArea.getText();
        setHighlightAT(outputText, hilitOuput, painterOuput);
        checkTokenID(outputText, hilitOuput, painterOuput);
}//GEN-LAST:event_convertButtonActionPerformed

    /**
     * set highlight cho body chua A va T trong ouput area
     * @param text
     * @param hilit
     * @param painter
     */
    private void setHighlightAT(String text, Highlighter hilit, Highlighter.HighlightPainter painter) {
        int position = -1;
        /*
         * Set highlight cho Agent
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.magenta);
        while ((position = text.indexOf("&&A ", position)) != -1) {
            try {
                hilit.addHighlight(position + 2, position + 3, painter);
                position++;
            } catch (BadLocationException ex) {
                Logger.getLogger(ConvertPanel.class.getName()).log(Level.SEVERE, null, ex);
            }// end try catch
        }// end while position

        /*
         * Set highlight cho Target
         */
        position = -1;
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.yellow);
        while ((position = text.indexOf("&&T ", position)) != -1) {
            try {
                hilit.addHighlight(position + 2, position + 3, painter);
                position++;
            } catch (BadLocationException ex) {
                Logger.getLogger(ConvertPanel.class.getName()).log(Level.SEVERE, null, ex);
            }// end try catch
        }// end while position
    }

    /**
     * Kiem tra tokenID sau khi convert co lien tuc khong, neu sai thi highlight voi mau do
     * @param text
     * @param hilit
     * @param painter
     */
    private void checkTokenID(String text, Highlighter hilit, Highlighter.HighlightPainter painter) {
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.red);
        /*
         * erroPositionList luu cac vi tri tokenID co loi trong toan bo output area
         */
        LinkedList<Integer> errorPositionList = new LinkedList<Integer>();
        /*
         * lineMap co key la vi tri bat dau cua 1 cau trong output area, value la 1 map luu cac thanh phan
         * body cua cau va tokenID cua body do
         */
        Map<Integer, Map> lineMap = new LinkedHashMap<Integer, Map>();
        /*
         * startLine la vi tri bat dau cua 1 cau
         */
        int startLine = 0;
        String[] lines = text.split("\r\n");
        for (String line : lines) {
            Map<String, Integer> tokenIDMap = new LinkedHashMap<String, Integer>();
            /*
             * Chi lay ra cac thanh phan trong body cua cau, ngan cach boi dau trang
             */
            String[] bodies = line.split("\t")[2].split("\\s+");
            for (String body : bodies) {
                String tokenID = body.split("&&")[0];
                tokenIDMap.put(body, new Integer(tokenID));
            }// end for body
            lineMap.put(startLine, tokenIDMap);
            startLine += line.length();
        }// end for line
        errorPositionList = getErrorPositionList(text, lineMap);
        /*
         * Set highlight cho cac vi tri loi
         */
        for (Integer errorPosition : errorPositionList) {
            int end = text.indexOf("&&", errorPosition);
            try {
                hilit.addHighlight(errorPosition, end, painter);
            } catch (BadLocationException ex) {
                Logger.getLogger(ConvertPanel.class.getName()).log(Level.SEVERE, null, ex);
            }// end try catch
        }// end for errorPosition

    }// end checkTokenID method

    /**
     * Xac dinh vi tri bi loi trong text. Cac gia tri tokenID trong 1 cau phai tang dan voi buoc la 1
     * va bat dau tu 0
     * @param tokenIDList
     * @return
     */
    private LinkedList<Integer> getErrorPositionList(String text, Map<Integer, Map> lineMap) {
        LinkedList<Integer> errorList = new LinkedList<Integer>();
        for (Map.Entry<Integer, Map> entry : lineMap.entrySet()) {
            int startLine = entry.getKey();
            int i = 0;
            LinkedHashMap<String, Integer> tokenIDMap = (LinkedHashMap<String, Integer>) entry.getValue();
            for (Map.Entry<String, Integer> tokenIDEntry : tokenIDMap.entrySet()) {
                String body = tokenIDEntry.getKey();
                int tokenID = tokenIDEntry.getValue();
                if (tokenID != i) {
                    int errorOffset = text.indexOf(body, startLine);
                    errorList.add(errorOffset);
                }// end if tokenID
                i++;
            }// end for tokenIDEntry
        }// end for entry
        return errorList;
    }// end getErrorTokenIDList method

    private void analyzeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_analyzeButtonActionPerformed
        // TODO add your handling code here:
        rowLine = inputTable.getSelectedRow();
        if (rowLine != -1) {
            String orgLine = (String) inputModel.getValueAt(rowLine, 0);
            if (orgLine.startsWith("\uFEFF")) {
                /*
                 * Bo ky tu BOM o dau dong
                 */
                orgLine = orgLine.substring(1);
            }// end if
            String inputLineForSentence = ConvertText.convertForSentence(orgLine);
            sentence = new Sentence(inputLineForSentence);
            entityMap = sentence.getEntityMap();
            JComboBox comboBox = new JComboBox();
            for (Map.Entry<Integer, Object[]> entry : entityMap.entrySet()) {
                comboBox.addItem(getEntityWords(sentence, entry));
            }// end for entry
            convertTable.getColumnModel().getColumn(0).setCellEditor(new DefaultCellEditor(comboBox));
            convertTable.getColumnModel().getColumn(1).setCellEditor(new DefaultCellEditor(comboBox));
            JOptionPane.showMessageDialog(null, "Found " + entityMap.size() + " entity in line",
                    "Information", JOptionPane.INFORMATION_MESSAGE);
        } else {
            JOptionPane.showMessageDialog(null, "Please, select line to analyze", "Warning", JOptionPane.WARNING_MESSAGE);
        }// end if rowLine
}//GEN-LAST:event_analyzeButtonActionPerformed

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
        // TODO add your handling code here:
        convertModel.addRow(new Vector());
        int row = convertModel.getRowCount();
        convertModel.setValueAt(false, row - 1, 2);
}//GEN-LAST:event_addButtonActionPerformed

    private void removeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeButtonActionPerformed
        // TODO add your handling code here:
        int[] rows = convertTable.getSelectedRows();
        if (rows.length == 0) {
            String message = "No selected row to delete";
            JOptionPane.showMessageDialog(null, message, "Warning", JOptionPane.WARNING_MESSAGE);
        } else {
            for (int i = rows.length - 1; i >= 0; i--) {
                convertModel.removeRow(rows[i]);
            }
        }
}//GEN-LAST:event_removeButtonActionPerformed

    private void clearOutputButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearOutputButtonActionPerformed
        // TODO add your handling code here:
        outputArea.setText("");
}//GEN-LAST:event_clearOutputButtonActionPerformed

    private void loadButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadButtonActionPerformed
        // TODO add your handling code here:
        /*
         * Reset field
         */
        outputArea.setText("");
        lineArea.setText("");
        count = 1;

        if (inputModel.getRowCount() > 0) {
            inputModel.getDataVector().removeAllElements();
        }
        String path = mapConfig.get(Config.DIRECTORY_PATH);
        JFileChooser fc = new JFileChooser(path);
        fc.setFileFilter(new TextFilter());
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        int val = fc.showOpenDialog(null);
        if (val == JFileChooser.APPROVE_OPTION) {
            BufferedReader in = null;
            try {
                File f = fc.getSelectedFile();
                fileName = f.getName();
                in = ReadWriteFile.readFile(f, "UTF-8");
                String line = null;
                while ((line = in.readLine()) != null) {
                    if (!line.equals("")) {
                        Object[] dataLine = {line};
                        inputModel.addRow(dataLine);
                    }
                }
            } catch (Exception ex) {
                Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                try {
                    in.close();
                } catch (IOException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
}//GEN-LAST:event_loadButtonActionPerformed

    private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed
        // TODO add your handling code here:
        convertModel.getDataVector().removeAllElements();
        convertModel.fireTableDataChanged();
}//GEN-LAST:event_clearButtonActionPerformed

    private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveButtonActionPerformed
        // TODO add your handling code here:
//        String path = mapConfig.get(Config.DIRECTORY_PATH);
        JFileChooser fc = new JFileChooser(savePath);

        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fc.setFileFilter(new TextFilter());
        fc.setSelectedFile(new File(fileName));
        int val = fc.showSaveDialog(null);
        if (val == JFileChooser.APPROVE_OPTION) {
            PrintWriter out = null;
            try {
                File f = fc.getSelectedFile();
                File file = null;
                if (f.getName().contains(".")) {
                    file = f;
                } else {
                    file = new File(f.getAbsolutePath() + ".txt");
                }
                out = ReadWriteFile.writeFile(file, "UTF-8");
                out.print(outputArea.getText());
            } catch (Exception ex) {
                Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                out.close();
                JOptionPane.showMessageDialog(null, "Save done");
            }
        }
}//GEN-LAST:event_saveButtonActionPerformed

    private void resetCountButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resetCountButtonActionPerformed
        // TODO add your handling code here:
        count = 1;
}//GEN-LAST:event_resetCountButtonActionPerformed

    private void openItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openItemActionPerformed
        // TODO add your handling code here:
        String line = (String) inputModel.getValueAt(inputTable.getSelectedRow(), 0);
        lineAreaDialog.setText(line);
        openDialog.pack();
        openDialog.setVisible(true);
}//GEN-LAST:event_openItemActionPerformed

    private void inputTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_inputTableMouseClicked
        Point pointClick = evt.getPoint();
        int row = inputTable.rowAtPoint(pointClick);
        inputTable.setRowSelectionInterval(row, row);
        lineArea.setText(inputModel.getValueAt(row, 0).toString());
        setHighlightLineArea(lineArea, hilitLine, painterLine);

        /*
         * clear button action
         */
        convertModel.getDataVector().removeAllElements();
        convertModel.fireTableDataChanged();
    }//GEN-LAST:event_inputTableMouseClicked

    private void inputTableKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_inputTableKeyReleased
        if (evt.getKeyCode() == KeyEvent.VK_DOWN || evt.getKeyCode() == KeyEvent.VK_UP) {
            int row = inputTable.getSelectedRow();
            if (row != -1) {
                lineArea.setText(inputModel.getValueAt(row, 0).toString());
            }// end if row
            setHighlightLineArea(lineArea, hilitLine, painterLine);

            /*
             * clear button action
             */
            convertModel.getDataVector().removeAllElements();
            convertModel.fireTableDataChanged();
        }// end if VK_Down VK_Up
    }//GEN-LAST:event_inputTableKeyReleased

    /**
     * Set highlight cho doi tuong lineArea
     * @param area
     * @param hilit
     * @param painter
     */
    private void setHighlightLineArea(JTextArea area, Highlighter hilit, Highlighter.HighlightPainter painter) {
        String text = area.getText();
        /*
         * Set CYAN cho per
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.CYAN);
        setHighlightEntity(text, hilit, painter, ENTITY.PER);
        /*
         * Set Light_Gray cho loc
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.LIGHT_GRAY);
        setHighlightEntity(text, hilit, painter, ENTITY.LOC);
        /*
         * Set Magenta cho org
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.MAGENTA);
        setHighlightEntity(text, hilit, painter, ENTITY.ORG);
        /*
         * Set Blue cho pos
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE);
        setHighlightEntity(text, hilit, painter, ENTITY.POS);
        /*
         * Set Yellow cho job
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.YELLOW);
        setHighlightEntity(text, hilit, painter, ENTITY.JOB);
        /*
         * Set Orange cho date
         */
        painter = new DefaultHighlighter.DefaultHighlightPainter(Color.ORANGE);
        setHighlightEntity(text, hilit, painter, ENTITY.DATE);
    }// end setHighlightLineArea

    private void setHighlightEntity(String text, Highlighter hilit, Highlighter.HighlightPainter painter, ENTITY entity) {
        int position = -1;
        int offset = 0;
        while ((position = text.toUpperCase().indexOf(entity.getStartTag(), offset)) != -1) {
            int start = position + entity.getStartLength() + 1;
            int end = text.toUpperCase().indexOf(entity.getEndTag(), start);
            if (start < end) {
                try {
                    hilit.addHighlight(start, end - 1, painter);
                    offset = end;
                } catch (BadLocationException ex) {
                    Logger.getLogger(ConvertPanel.class.getName()).log(Level.SEVERE, null, ex);
                    offset = start;
                }// end try catch
            }// end if start < end
        }// end while
    }

    private void removeItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeItemActionPerformed
        int row = inputTable.getSelectedRow();
        if (row != -1) {
            lineArea.setText("");
            inputModel.removeRow(row);
        }// end if row
    }//GEN-LAST:event_removeItemActionPerformed

    private void sizeSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sizeSpinnerStateChanged
        // TODO add your handling code here:
        int size = (Integer) sizeSpinner.getValue();
        Font oldFont = lineArea.getFont();
        Font changedFont = oldFont.deriveFont((float) size);
        GUIFunction.setFontArea(lineArea, changedFont);
        mapConfig.put(Config.LINE_FONT_SIZE, Integer.toString(size));
    }//GEN-LAST:event_sizeSpinnerStateChanged

    private void savePathTFMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_savePathTFMousePressed
        // TODO add your handling code here:
        JFileChooser fc = new JFileChooser(mapConfig.get(Config.DIRECTORY_PATH));
        fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        int val = fc.showOpenDialog(null);
        if (val == JFileChooser.APPROVE_OPTION) {
            savePath = fc.getSelectedFile().getAbsolutePath();
            savePathTF.setText(savePath);
        }
    }//GEN-LAST:event_savePathTFMousePressed

    /**
     * Get all words of an entity in line
     * @param sentence The sentence is analyzed
     * @param entry An element of entityMap
     * @return A String has format: id entity.entity type-entity's word
     */
    private String getEntityWords(Sentence sentence, Map.Entry<Integer, Object[]> entry) {
        StringBuilder sb = new StringBuilder();
        int id = entry.getKey();
        Object[] values = entry.getValue();
        ENTITY entity = (ENTITY) values[0];
        int beginOffset = (Integer) values[1];
        int endOffset = (Integer) values[2];
        String entityString = sentence.fragment(beginOffset, endOffset).toString().replaceAll(" ", "_");
        sb.append(id);
        sb.append(".");
        sb.append(entity.getName());
        sb.append("-");
        sb.append(entityString);
        return sb.toString();
    }

    /**
     * Get all words of an entity in line
     * @param sentence The sentence is analyzed
     * @param values Value of an element of entityMap
     * @return A String has format: id entity - entity type - entity's word
     */
    private String getEntityWords(Sentence sentence, Object[] values) {
        StringBuilder sb = new StringBuilder();
        int id = (Integer) values[1];
        int endOffset = (Integer) values[2];
        ENTITY entity = (ENTITY) values[0];
        String entityString = sentence.fragment(id, endOffset).toString().replaceAll(" ", "_");
        sb.append(id);
        sb.append(".");
        sb.append(entity.getName());
        sb.append("-");
        sb.append(entityString);
        return sb.toString();
    }

    /**
     * Get offset in selected item in Combo (start with 0)
     */
    private int getOffsetFromCombo(String itemCombo) {
        String[] elements = itemCombo.split("\\.");
        return Integer.valueOf(elements[0]);
    }

    // <editor-fold defaultstate="collapsed" desc="PopupListener class">
    class PopupListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e);
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            if (e.isPopupTrigger()) {
                showPopup(e);
            }
        }

        private void showPopup(MouseEvent e) {
            popupMenu.show(e.getComponent(), e.getX(), e.getY());
            Point point = e.getPoint();
            int row = inputTable.rowAtPoint(point);
            inputTable.setRowSelectionInterval(row, row);
        }
    }
    // </editor-fold>
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addButton;
    private javax.swing.JButton analyzeButton;
    private javax.swing.JButton clearButton;
    private javax.swing.JButton clearOutputButton;
    private javax.swing.JButton convertButton;
    private javax.swing.JTable convertTable;
    private javax.swing.JTable inputTable;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JScrollPane jScrollPane5;
    private javax.swing.JTextArea lineArea;
    private javax.swing.JTextArea lineAreaDialog;
    private javax.swing.JButton loadButton;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JDialog openDialog;
    private javax.swing.JMenuItem openItem;
    private javax.swing.JTextArea outputArea;
    private javax.swing.JPopupMenu popupMenu;
    private javax.swing.JButton removeButton;
    private javax.swing.JMenuItem removeItem;
    private javax.swing.JButton resetCountButton;
    private javax.swing.JButton saveButton;
    private javax.swing.JTextField savePathTF;
    private javax.swing.JSpinner sizeSpinner;
    // End of variables declaration//GEN-END:variables
    private HashMap<String, String> mapConfig;
    private DefaultTableModel convertModel;
    private DefaultTableModel inputModel;
    private Sentence sentence;
    private Map<Integer, Object[]> entityMap;
    private int rowLine; /* id of line in file*/

    private int count;   /* id of line in output*/

    /*
     * highlight va highlightPainter cho ouputArea
     */
    private Highlighter hilitOuput;
    private Highlighter.HighlightPainter painterOuput;
    /*
     * highlight va highlightPainter cho lineArea
     */
    private Highlighter hilitLine;
    private Highlighter.HighlightPainter painterLine;
    /*
     * Directory to save
     */
    private String savePath;
    /*
     * File path cua file load
     */
    private String fileName;
}
